package com.yin.waimai.service.impl;

import com.yin.waimai.dto.DeliveryPersonDTO;
import com.yin.waimai.enums.DeliveryPersonStatus;
import com.yin.waimai.model.DeliveryPerson;
import com.yin.waimai.repository.DeliveryPersonRepository;
import com.yin.waimai.service.DeliveryPersonService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Point;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 配送人员服务实现类
 */
@Service
public class DeliveryPersonServiceImpl implements DeliveryPersonService {

    private static final Logger log = LoggerFactory.getLogger(DeliveryPersonServiceImpl.class);

    private final DeliveryPersonRepository deliveryPersonRepository;

    @Autowired
    public DeliveryPersonServiceImpl(DeliveryPersonRepository deliveryPersonRepository) {
        this.deliveryPersonRepository = deliveryPersonRepository;
    }

    @Override
    public DeliveryPersonDTO createDeliveryPerson(DeliveryPersonDTO deliveryPersonDTO) {
        log.info("Creating new delivery person: {}", deliveryPersonDTO.getName());
        
        // 如果电话号码为空，生成一个随机电话号码
        if (deliveryPersonDTO.getPhone() == null || deliveryPersonDTO.getPhone().isEmpty()) {
            // 生成一个唯一的电话号码
            String uniquePhone = "13800" + System.currentTimeMillis() % 10000000;
            try {
                while (deliveryPersonRepository.findByPhone(uniquePhone).isPresent()) {
                    Thread.sleep(10); // 短暂延迟以改变时间戳
                    uniquePhone = "13800" + System.currentTimeMillis() % 10000000;
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            deliveryPersonDTO.setPhone(uniquePhone);
            log.info("Generated random phone number: {}", deliveryPersonDTO.getPhone());
        }
        
        // 检查电话号码是否已存在
        if (deliveryPersonRepository.findByPhone(deliveryPersonDTO.getPhone()).isPresent()) {
            log.warn("Phone number already exists: {}", deliveryPersonDTO.getPhone());
            throw new IllegalArgumentException("Phone number already exists");
        }
        
        // 检查用户名是否已存在
        if (deliveryPersonRepository.findByName(deliveryPersonDTO.getName()).isPresent()) {
            log.warn("Delivery person with name already exists: {}", deliveryPersonDTO.getName());
            throw new IllegalArgumentException("Delivery person with this name already exists");
        }
        
        DeliveryPerson deliveryPerson = convertToEntity(deliveryPersonDTO);
        
        // 设置初始状态为空闲
        if (deliveryPerson.getStatus() == null) {
            deliveryPerson.setStatus(DeliveryPersonStatus.IDLE);
        }
        
        DeliveryPerson savedDeliveryPerson = deliveryPersonRepository.save(deliveryPerson);
        log.info("Delivery person created with ID: {}", savedDeliveryPerson.getId());
        
        return convertToDTO(savedDeliveryPerson);
    }

    @Override
    public Optional<DeliveryPersonDTO> findById(String id) {
        log.debug("Finding delivery person by ID: {}", id);
        return deliveryPersonRepository.findById(id).map(this::convertToDTO);
    }

    @Override
    public Optional<DeliveryPersonDTO> findByPhone(String phone) {
        log.debug("Finding delivery person by phone: {}", phone);
        return deliveryPersonRepository.findByPhone(phone).map(this::convertToDTO);
    }

    @Override
    public Optional<DeliveryPersonDTO> findByName(String name) {
        log.debug("Finding delivery person by name: {}", name);
        return deliveryPersonRepository.findByName(name).map(this::convertToDTO);
    }

    @Override
    public List<DeliveryPersonDTO> findAll() {
        log.debug("Finding all delivery persons");
        return deliveryPersonRepository.findAll().stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public List<DeliveryPersonDTO> findByStatus(DeliveryPersonStatus status) {
        log.debug("Finding delivery persons by status: {}", status);
        return deliveryPersonRepository.findByStatus(status).stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public DeliveryPersonDTO updateDeliveryPerson(String id, DeliveryPersonDTO deliveryPersonDTO) {
        log.info("Updating delivery person with ID: {}", id);
        
        DeliveryPerson existingDeliveryPerson = deliveryPersonRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("Delivery person not found with ID: " + id));
        
        // 检查电话号码是否已被其他配送员使用
        if (!existingDeliveryPerson.getPhone().equals(deliveryPersonDTO.getPhone()) &&
                deliveryPersonRepository.findByPhone(deliveryPersonDTO.getPhone()).isPresent()) {
            log.warn("Phone number already exists: {}", deliveryPersonDTO.getPhone());
            throw new IllegalArgumentException("Phone number already exists");
        }
        
        // 更新字段
        existingDeliveryPerson.setName(deliveryPersonDTO.getName());
        existingDeliveryPerson.setPhone(deliveryPersonDTO.getPhone());
        
        // 如果提供了位置信息，则更新
        if (deliveryPersonDTO.getCurrentLocation() != null && deliveryPersonDTO.getCurrentLocation().length == 2) {
            existingDeliveryPerson.setCurrentLocation(
                    new GeoJsonPoint(deliveryPersonDTO.getCurrentLocation()[0], deliveryPersonDTO.getCurrentLocation()[1]));
        }
        
        // 如果提供了状态信息，则更新
        if (deliveryPersonDTO.getStatus() != null) {
            existingDeliveryPerson.setStatus(deliveryPersonDTO.getStatus());
        }
        
        DeliveryPerson updatedDeliveryPerson = deliveryPersonRepository.save(existingDeliveryPerson);
        log.info("Delivery person updated: {}", updatedDeliveryPerson.getId());
        
        return convertToDTO(updatedDeliveryPerson);
    }

    @Override
    public DeliveryPersonDTO updateStatus(String id, DeliveryPersonStatus status) {
        log.info("Updating delivery person status. ID: {}, New status: {}", id, status);
        
        DeliveryPerson deliveryPerson = deliveryPersonRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("Delivery person not found with ID: " + id));
        
        deliveryPerson.setStatus(status);
        DeliveryPerson updatedDeliveryPerson = deliveryPersonRepository.save(deliveryPerson);
        log.info("Delivery person status updated: {}", updatedDeliveryPerson.getId());
        
        return convertToDTO(updatedDeliveryPerson);
    }

    @Override
    public DeliveryPersonDTO updateLocation(String id, double longitude, double latitude) {
        log.info("Updating delivery person location. ID: {}, Location: [{}, {}]", id, longitude, latitude);
        
        DeliveryPerson deliveryPerson = deliveryPersonRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("Delivery person not found with ID: " + id));
        
        deliveryPerson.setCurrentLocation(new GeoJsonPoint(longitude, latitude));
        DeliveryPerson updatedDeliveryPerson = deliveryPersonRepository.save(deliveryPerson);
        log.info("Delivery person location updated: {}", updatedDeliveryPerson.getId());
        
        return convertToDTO(updatedDeliveryPerson);
    }

    @Override
    public void deleteDeliveryPerson(String id) {
        log.info("Deleting delivery person with ID: {}", id);
        
        if (!deliveryPersonRepository.existsById(id)) {
            log.warn("Cannot delete. Delivery person not found with ID: {}", id);
            throw new IllegalArgumentException("Delivery person not found with ID: " + id);
        }
        
        deliveryPersonRepository.deleteById(id);
        log.info("Delivery person deleted: {}", id);
    }

    @Override
    public List<DeliveryPersonDTO> findNearby(Point location, Distance distance) {
        log.debug("Finding nearby delivery persons. Location: {}, Distance: {}", location, distance);
        // 注意：这里需要在DeliveryPersonRepository中实现findByCurrentLocationNear方法
        return deliveryPersonRepository.findByCurrentLocationNear(location, distance).stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public List<DeliveryPersonDTO> findNearbyIdle(Point location, Distance distance) {
        log.debug("Finding nearby idle delivery persons. Location: {}, Distance: {}", location, distance);
        // 注意：这里需要在DeliveryPersonRepository中实现findByCurrentLocationNearAndStatus方法
        return deliveryPersonRepository.findByCurrentLocationNearAndStatus(location, distance, DeliveryPersonStatus.IDLE).stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public boolean existsById(String id) {
        log.debug("Checking if delivery person exists by ID: {}", id);
        return deliveryPersonRepository.existsById(id);
    }

    /**
     * 将实体转换为DTO
     */
    private DeliveryPersonDTO convertToDTO(DeliveryPerson deliveryPerson) {
        if (deliveryPerson == null) {
            return null;
        }
        
        DeliveryPersonDTO dto = new DeliveryPersonDTO();
        dto.setId(deliveryPerson.getId());
        dto.setName(deliveryPerson.getName());
        dto.setPhone(deliveryPerson.getPhone());
        dto.setStatus(deliveryPerson.getStatus());
        
        // 转换GeoJsonPoint为经纬度数组
        if (deliveryPerson.getCurrentLocation() != null) {
            dto.setCurrentLocation(new Double[] {
                    deliveryPerson.getCurrentLocation().getX(), // 经度
                    deliveryPerson.getCurrentLocation().getY()  // 纬度
            });
        }
        
        return dto;
    }

    /**
     * 将DTO转换为实体
     */
    private DeliveryPerson convertToEntity(DeliveryPersonDTO dto) {
        if (dto == null) {
            return null;
        }
        
        DeliveryPerson entity = new DeliveryPerson();
        entity.setId(dto.getId()); // 如果是新建，ID应该为null
        entity.setName(dto.getName());
        entity.setPhone(dto.getPhone());
        entity.setStatus(dto.getStatus());
        
        // 转换经纬度数组为GeoJsonPoint
        if (dto.getCurrentLocation() != null && dto.getCurrentLocation().length == 2) {
            entity.setCurrentLocation(
                    new GeoJsonPoint(dto.getCurrentLocation()[0], dto.getCurrentLocation()[1]));
        }
        
        return entity;
    }

    @Override
    public List<DeliveryPersonDTO> getActiveDeliveryPersons() {
        log.debug("Finding active delivery persons");
        // 查找所有非离线状态的配送员
        return deliveryPersonRepository.findAll().stream()
                .filter(dp -> dp.getStatus() != DeliveryPersonStatus.OFFLINE)
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }
    
    @Override
    public long countDeliveryPersons() {
        log.debug("Counting all delivery persons");
        return deliveryPersonRepository.count();
    }
}